package org.jpropelleralt.universe;

import org.jpropelleralt.box.Box;
import org.jpropelleralt.change.Change;
import org.jpropelleralt.reaction.Reaction;
import org.jpropelleralt.view.View;

/**
 * Internal features of {@link Universe}, only useful
 * to {@link Box}es, etc.
 */
public interface UniverseInternal {

	/**
	 * Called before a {@link Box} is read.
	 * Must call {@link #concludeRead(Box)} when finished,
	 * preferably at the start of a try...finally 
	 * @param box 		{@link Box} about to be read
	 */
	public void prepareRead(Box box);

	/**
	 * Called after a {@link Box} is read.
	 * Must follow a call to {@link #prepareRead(Box)},
	 * preferably in the finally block of a try...finally
	 * @param box 		{@link Box} that has been read
	 */
	public void concludeRead(Box box);
	
	/**
	 * Called before a {@link Box} is written to.
	 * Must call {@link #concludeWrite(Box)} when finished,
	 * preferably at the start of a try...finally
	 * @param box 		{@link Box} about to be written
	 */
	public void prepareWrite(Box box);
	
	/**
	 * Called after each actual change to a {@link Box}.
	 * Must follow a call to {@link #prepareRead(Box)},
	 * preferably within the try block of a a try...finally
	 * @param box 		{@link Box} that has changed
	 * @param change	The change that just has been made
	 */
	public void propagateWrite(Box box, Change change);

	/**
	 * Called after a {@link Box} is written.
	 * Must follow a call to {@link #prepareWrite(Box)},
	 * preferably as a try...finally
	 * @param box 		{@link Box} that has written
	 */
	public void concludeWrite(Box box);
	
	/**
	 * Called before a {@link Box} has {@link View} list changed.
	 * Must call {@link #concludeViewChange(Box)} when finished,
	 * preferably at the start of a try...finally 
	 * @param box 		{@link Box} about to have {@link View} list changed.
	 */
	public void prepareViewChange(Box box);

	/**
	 * Called after a {@link Box} has {@link View} list changed.
	 * Must follow a call to {@link #prepareViewChange(Box)},
	 * preferably in the finally block of a try...finally
	 * @param box 		{@link Box} that has had {@link View} list changed.
	 */
	public void concludeViewChange(Box box);

	/**
	 * Called before a {@link Box} has {@link Reaction} list changed.
	 * Must call {@link #concludeReactionChange(Box)} when finished,
	 * preferably at the start of a try...finally 
	 * @param box 		{@link Box} about to have {@link Reaction} list changed.
	 */
	public void prepareReactionChange(Box box);

	/**
	 * Called after a {@link Box} has {@link Reaction} list changed.
	 * Must follow a call to {@link #prepareReactionChange(Box)},
	 * preferably in the finally block of a try...finally
	 * @param box 		{@link Box} that has had {@link Reaction} list changed.
	 */
	public void concludeReactionChange(Box box);
	
	/**
	 * Lock the entire {@link Universe}.
	 * Until {@link #release()} is called, only the current thread
	 * will be able to read or write state. No notifications will
	 * be sent to {@link View}s.
	 * {@link Reaction}s will only be applied if state is read.
	 * Must call {@link #release()} when finished,
	 * preferably at the start of a try...finally 
	 */
	public void acquire();

	/**
	 * Release the lock on the entire {@link Universe}.
	 * Must follow a call to {@link #lock()},
	 * preferably in the finally block of a try...finally
	 */
	public void release();

}
